import pygame
import sys
import os
import json

# 初始化 pygame
pygame.init()

# 棋子类
class Piece:
    def __init__(self, x, y, color, name, red_pieces, black_pieces, piece_size):
        self.x = x
        self.y = y
        self.color = color
        self.name = name
        self.red_pieces = red_pieces
        self.black_pieces = black_pieces
        self.piece_size = piece_size
        if color == "red":
            self.image = pygame.image.load(self.red_pieces[name]).convert_alpha()
        else:
            self.image = pygame.image.load(self.black_pieces[name]).convert_alpha()
        self.image = pygame.transform.scale(self.image, (int(self.piece_size), int(self.piece_size)))

    def draw(self, screen, board_reversed, square_size):
        draw_x = self.x
        draw_y = self.y
        if board_reversed:
            draw_x = 8 - self.x
            draw_y = 9 - self.y
        center_x = draw_x * square_size + square_size // 2
        center_y = draw_y * square_size + square_size // 2
        screen.blit(self.image, (center_x - self.image.get_width() // 2, center_y - self.image.get_height() // 2))

    def can_move(self, new_x, new_y, pieces):
        if new_x < 0 or new_x > 8 or new_y < 0 or new_y > 9:
            return False
        for piece in pieces:
            if piece.x == new_x and piece.y == new_y:
                if piece.color == self.color:
                    return False
                break
        if self.name == "車":
            return self.can_move_rook(new_x, new_y, pieces)
        elif self.name == "馬":
            return self.can_move_knight(new_x, new_y, pieces)
        elif self.name in ["相", "象"]:
            return self.can_move_bishop(new_x, new_y, pieces)
        elif self.name in ["仕", "士"]:
            return self.can_move_advisor(new_x, new_y, pieces)
        elif self.name in ["帥", "將"]:
            return self.can_move_king(new_x, new_y, pieces)
        elif self.name == "炮":
            return self.can_move_cannon(new_x, new_y, pieces)
        elif self.name in ["兵", "卒"]:
            return self.can_move_pawn(new_x, new_y, pieces)
        return False

    def can_move_rook(self, new_x, new_y, pieces):
        if self.x != new_x and self.y != new_y:
            return False
        if self.x == new_x:
            step = 1 if new_y > self.y else -1
            for y in range(self.y + step, new_y, step):
                if any(piece.x == self.x and piece.y == y for piece in pieces):
                    return False
        else:
            step = 1 if new_x > self.x else -1
            for x in range(self.x + step, new_x, step):
                if any(piece.x == x and piece.y == self.y for piece in pieces):
                    return False
        return True

    def can_move_knight(self, new_x, new_y, pieces):
        dx = abs(new_x - self.x)
        dy = abs(new_y - self.y)
        if not ((dx == 2 and dy == 1) or (dx == 1 and dy == 2)):
            return False
        if dx == 2:
            mid_x = (self.x + new_x) // 2
            if any(piece.x == mid_x and piece.y == self.y for piece in pieces):
                return False
        else:
            mid_y = (self.y + new_y) // 2
            if any(piece.x == self.x and piece.y == mid_y for piece in pieces):
                return False
        return True

    def can_move_bishop(self, new_x, new_y, pieces):
        dx = abs(new_x - self.x)
        dy = abs(new_y - self.y)
        if dx != 2 or dy != 2:
            return False
        mid_x = (self.x + new_x) // 2
        mid_y = (self.y + new_y) // 2
        if any(piece.x == mid_x and piece.y == mid_y for piece in pieces):
            return False
        return True

    def can_move_advisor(self, new_x, new_y, pieces):
        dx = abs(new_x - self.x)
        dy = abs(new_y - self.y)
        if dx != 1 or dy != 1:
            return False
        if new_x < 3 or new_x > 5 or (new_y > 2 and new_y < 7):
            return False
        return True

    def can_move_king(self, new_x, new_y, pieces):
        dx = abs(new_x - self.x)
        dy = abs(new_y - self.y)
        if dx + dy != 1:
            return False
        if new_x < 3 or new_x > 5 or (new_y > 2 and new_y < 7):
            return False
        return True

    def can_move_cannon(self, new_x, new_y, pieces):
        if self.x != new_x and self.y != new_y:
            return False
        count = 0
        if self.x == new_x:
            step = 1 if new_y > self.y else -1
            for y in range(self.y + step, new_y, step):
                if any(piece.x == self.x and piece.y == y for piece in pieces):
                    count += 1
        else:
            step = 1 if new_x > self.x else -1
            for x in range(self.x + step, new_x, step):
                if any(piece.x == x and piece.y == self.y for piece in pieces):
                    count += 1
        target_piece = next((piece for piece in pieces if piece.x == new_x and piece.y == new_y), None)
        if target_piece:
            return count == 1
        else:
            return count == 0

    def can_move_pawn(self, new_x, new_y, pieces):
        dx = abs(new_x - self.x)
        dy = abs(new_y - self.y)
        if dx + dy != 1:
            return False
        if self.color == "red":
            if new_y > self.y:
                return False
        else:
            if new_y < self.y:
                return False
        return True


# 游戏类
class \
    Game:
    def __init__(self):
        # 定义常量
        self.BOARD_WIDTH = 800  # 棋盘宽度
        self.BOARD_HEIGHT = 877  # 棋盘高度
        self.INFO_WIDTH = 550  # 右侧空白区域宽度
        self.WIDTH = self.BOARD_WIDTH + self.INFO_WIDTH  # 窗口总宽度
        self.HEIGHT = self.BOARD_HEIGHT  # 窗口高度
        self.SQUARE_SIZE = self.BOARD_WIDTH // 9  # 每个格子的大小
        self.PIECE_SIZE = self.SQUARE_SIZE * 0.8  # 棋子大小
        self.SELECTION_COLOR = (0, 255, 0)  # 选中框颜色
        self.RED_TURN = True  # 红方先手
        self.BOARD_REVERSED = False

        # 图片路径
        self.IMAGE_PATH = r"C:\Users\rulin\Desktop\images\images"

        # 加载棋盘图片
        board_image_path = os.path.join(self.IMAGE_PATH, "board.png")
        self.BOARD_IMAGE = pygame.image.load(board_image_path)
        self.BOARD_IMAGE = pygame.transform.scale(self.BOARD_IMAGE, (self.BOARD_WIDTH, self.BOARD_HEIGHT))

        # 棋子图片映射
        self.RED_PIECES = {
            "車": os.path.join(self.IMAGE_PATH, "red_che.png"),
            "馬": os.path.join(self.IMAGE_PATH, "red_ma.png"),
            "相": os.path.join(self.IMAGE_PATH, "red_xiang.png"),
            "仕": os.path.join(self.IMAGE_PATH, "red_shi.png"),
            "帥": os.path.join(self.IMAGE_PATH, "red_shuai.png"),
            "炮": os.path.join(self.IMAGE_PATH, "red_pao.png"),
            "兵": os.path.join(self.IMAGE_PATH, "red_bing.png")
        }
        self.BLACK_PIECES = {
            "車": os.path.join(self.IMAGE_PATH, "black_ju.png"),
            "馬": os.path.join(self.IMAGE_PATH, "black_ma.png"),
            "象": os.path.join(self.IMAGE_PATH, "black_xiang.png"),
            "士": os.path.join(self.IMAGE_PATH, "black_shi.png"),
            "將": os.path.join(self.IMAGE_PATH, "black_jiang.png"),
            "炮": os.path.join(self.IMAGE_PATH, "black_pao.png"),
            "卒": os.path.join(self.IMAGE_PATH, "black_zu.png")
        }
        self.GENERAL_CHECK_IMAGE = pygame.image.load(os.path.join(self.IMAGE_PATH, "general_check.png"))
        self.GENERAL_CHECK_IMAGE = pygame.transform.scale(self.GENERAL_CHECK_IMAGE, (200, 200))

        # 创建窗口
        self.screen = pygame.display.set_mode((self.WIDTH, self.HEIGHT))
        pygame.display.set_caption("双人象棋")

        # 初始化棋子
        self.pieces = []
        self.init_pieces()

        # 历史记录
        self.history = []

        # 输入框相关
        self.input_text = ""
        self.input_active = False
        self.input_rect = pygame.Rect(self.BOARD_WIDTH + 20, 300, 260, 40)  # 输入框位置和大小
        self.font = pygame.font.SysFont("simhei", 36)  # 使用黑体字体

    # 初始化棋子
    def init_pieces(self):
        # 红方棋子
        red_pieces = [
            Piece(0, 9, "red", "車", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(1, 9, "red", "馬", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(2, 9, "red", "相", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(3, 9, "red", "仕", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(4, 9, "red", "帥", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(5, 9, "red", "仕", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(6, 9, "red", "相", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(7, 9, "red", "馬", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(8, 9, "red", "車", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(1, 7, "red", "炮", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(7, 7, "red", "炮", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(0, 6, "red", "兵", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(2, 6, "red", "兵", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(4, 6, "red", "兵", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(6, 6, "red", "兵", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(8, 6, "red", "兵", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE)
        ]

        # 黑方棋子
        black_pieces = [
            Piece(0, 0, "black", "車", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(1, 0, "black", "馬", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(2, 0, "black", "象", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(3, 0, "black", "士", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(4, 0, "black", "將", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(5, 0, "black", "士", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(6, 0, "black", "象", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(7, 0, "black", "馬", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(8, 0, "black", "車", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(1, 2, "black", "炮", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(7, 2, "black", "炮", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(0, 3, "black", "卒", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(2, 3, "black", "卒", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(4, 3, "black", "卒", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(6, 3, "black", "卒", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE),
            Piece(8, 3, "black", "卒", self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE)
        ]

        self.pieces.extend(red_pieces)
        self.pieces.extend(black_pieces)

    # 绘制棋盘
    def draw_board(self):
        self.screen.blit(self.BOARD_IMAGE, (0, 0))

    # 绘制棋子
    def draw_pieces(self):
        for piece in self.pieces:
            piece.draw(self.screen, self.BOARD_REVERSED, self.SQUARE_SIZE)

    # 绘制游戏须知
    def draw_info(self):
        font = pygame.font.SysFont("simhei", 36)  # 使用黑体字体
        info_text = [
            "游戏须知：",
            "1. 红方先手，黑方后手。",
            "2. 按下 's' 键存档。",
            "3. 按下 'l' 键读档。",
            "4. 按下 'u' 键悔棋。",
            "5. 选定棋子后点击目标位置移动。",
            "6. 不符合规则则无法移动。",
            f"当前回合: {'红方' if self.RED_TURN else '黑方'}"
        ]
        y_offset = 20
        for line in info_text:
            text_surface = font.render(line, True, (0, 0, 0))  # 黑色字体
            self.screen.blit(text_surface, (self.BOARD_WIDTH + 20, y_offset))
            y_offset += 40

    # 绘制输入框
    def draw_input_box(self):
        pygame.draw.rect(self.screen, (255, 255, 255), self.input_rect, 2)  # 白色边框
        text_surface = self.font.render(self.input_text, True, (0, 0, 0))  # 黑色字体
        self.screen.blit(text_surface, (self.input_rect.x + 5, self.input_rect.y + 5))

    # 检查是否有一方获胜
    def check_win(self):
        red_king_alive = False
        black_king_alive = False
        for piece in self.pieces:
            if piece.name == "帥":
                red_king_alive = True
            elif piece.name == "將":
                black_king_alive = True
        if not red_king_alive:
            return "black"
        elif not black_king_alive:
            return "red"
        return None

    def check_general_check(self):
        # 找到红方和黑方的将（帅）
        red_king = None
        black_king = None
        for piece in self.pieces:
            if piece.name == "帥":
                red_king = piece
            elif piece.name == "將":
                black_king = piece

        if red_king and black_king:
            for piece in self.pieces:
                if piece.color == "black" and piece.can_move(red_king.x, red_king.y, self.pieces):
                    self.is_general_check = True
                    return
                elif piece.color == "red" and piece.can_move(black_king.x, black_king.y, self.pieces):
                    self.is_general_check = True
                    return
        self.is_general_check = False

    # 存档功能
    def save_game(self, filename="savegame.json"):
        print("正在保存游戏...")
        game_state = {
            "pieces": [],
            "red_turn": self.RED_TURN
        }
        for piece in self.pieces:
            game_state["pieces"].append({
                "x": piece.x,
                "y": piece.y,
                "color": piece.color,
                "name": piece.name
            })
        try:
            with open(filename, "w") as f:
                json.dump(game_state, f)
            print(f"游戏已保存到 {filename}")
        except Exception as e:
            print(f"保存游戏时出错: {e}")

    # 读档功能
    def load_game(self, filename="savegame.json"):
        try:
            with open(filename, "r") as f:
                game_state = json.load(f)
            self.pieces = []
            for piece_data in game_state["pieces"]:
                self.pieces.append(Piece(piece_data["x"], piece_data["y"], piece_data["color"], piece_data["name"], self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE))
            self.RED_TURN = game_state["red_turn"]
            print(f"游戏已从 {filename} 加载")
        except FileNotFoundError:
            print(f"存档文件 {filename} 不存在")
        except Exception as e:
            print(f"加载游戏时出错: {e}")

    # 保存当前状态到历史记录
    def save_state_to_history(self):
        state = {
            "pieces": [],
            "red_turn": self.RED_TURN
        }
        for piece in self.pieces:
            state["pieces"].append({
                "x": piece.x,
                "y": piece.y,
                "color": piece.color,
                "name": piece.name
            })
        self.history.append(state)
        print(f"已保存当前状态到历史记录，当前历史记录长度: {len(self.history)}")

    # 悔棋功能
    def undo(self):
        if len(self.history) > 1:  # 至少有两步才能悔棋
            self.history.pop()  # 移除当前状态
            prev_state = self.history[-1]  # 获取上一步状态
            self.pieces = []
            for piece_data in prev_state["pieces"]:
                self.pieces.append(Piece(piece_data["x"], piece_data["y"], piece_data["color"], piece_data["name"], self.RED_PIECES, self.BLACK_PIECES, self.PIECE_SIZE))
            self.RED_TURN = prev_state["red_turn"]
            print("悔棋成功")
        else:
            print("无法悔棋，历史记录为空")

    # 主循环
    def run(self):
        selected_piece = None
        running = True
        while running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    x, y = event.pos
                    if x < self.BOARD_WIDTH:  # 只在棋盘区域内响应点击
                        col = x // self.SQUARE_SIZE
                        row = y // self.SQUARE_SIZE
                        if selected_piece is None:
                            for piece in self.pieces:
                                if piece.x == col and piece.y == row:
                                    if (self.RED_TURN and piece.color == "red") or (not self.RED_TURN and piece.color == "black"):
                                        selected_piece = piece
                                        print(f"选中棋子: {selected_piece.name}, 颜色: {selected_piece.color}, 位置: ({selected_piece.x}, {selected_piece.y})")
                                    break
                        else:
                            print(f"目标位置: ({col}, {row})")
                            if selected_piece.can_move(col, row, self.pieces):
                                self.save_state_to_history()  # 保存当前状态到历史记录
                                for piece in self.pieces[:]:
                                    if piece.x == col and piece.y == row:
                                        self.pieces.remove(piece)
                                        break
                                selected_piece.x = col
                                selected_piece.y = row
                                self.RED_TURN = not self.RED_TURN
                            selected_piece = None
                    else:  # 点击右侧区域
                        if self.input_rect.collidepoint(event.pos):
                            self.input_active = True
                        else:
                            self.input_active = False
                elif event.type == pygame.KEYDOWN:
                    if self.input_active:
                        if event.key == pygame.K_RETURN:  # 按下回车键
                            print(f"输入的文字: {self.input_text}")
                            self.input_text = ""  # 清空输入框
                        elif event.key == pygame.K_BACKSPACE:  # 按下退格键
                            self.input_text = self.input_text[:-1]
                        else:
                            self.input_text += event.unicode  # 添加字符
                    else:
                        if event.key == pygame.K_s:  # 按下 's' 键保存游戏
                            print("检测到按下 's' 键")
                            self.save_game()
                        elif event.key == pygame.K_l:  # 按下 'l' 键加载游戏
                            print("检测到按下 'l' 键")
                            self.load_game()
                        elif event.key == pygame.K_u:  # 按下 'u' 键悔棋
                            print("检测到按下 'u' 键")
                            self.undo()

            # 清空右侧区域为白色
            pygame.draw.rect(self.screen, (255, 255, 255), (self.BOARD_WIDTH, 0, self.INFO_WIDTH, self.HEIGHT))

            # 绘制棋盘和棋子
            self.draw_board()
            self.draw_pieces()

            # 绘制游戏须知
            self.draw_info()

            # 绘制输入框
            self.draw_input_box()

            # 绘制选中框
            if selected_piece:
                pygame.draw.rect(self.screen, self.SELECTION_COLOR,
                                 (selected_piece.x * self.SQUARE_SIZE, selected_piece.y * self.SQUARE_SIZE, self.SQUARE_SIZE, self.SQUARE_SIZE), 2)

            # 检查胜负
            winner = self.check_win()
            if winner:
                font = pygame.font.SysFont("simhei", 74)  # 使用黑体字体
                text = font.render(f"{winner}方获胜！", True, (255, 0, 0))
                self.screen.blit(text, (self.WIDTH // 2 - text.get_width() // 2, self.HEIGHT // 2 - text.get_height() // 2))
                pygame.display.flip()
                pygame.time.wait(3000)
                running = False

            pygame.display.flip()

        # 退出 pygame
        pygame.quit()
        sys.exit()


# 启动游戏
if __name__ == "__main__":
    game = Game()
    game.run()